package service

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/spf13/cast"
	"google.golang.org/grpc"
	"net"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	balanceClient "zxs-micro-2/zxs-micro-balance-client/client"
	balanceConfig "zxs-micro-2/zxs-micro-balance-client/config"
	"zxs-micro-2/zxs-micro-business-server/report/config"
	"zxs-micro-2/zxs-micro-business-server/report/consts"
	"zxs-micro-2/zxs-micro-common/codec/http_codec"
	_ "zxs-micro-2/zxs-micro-common/codec/serializer"
	healthUtil "zxs-micro-2/zxs-micro-healthutil/service"
	"zxs-micro-2/zxs-micro-proto/businesspb/business"
	serverfindClient "zxs-micro-2/zxs-micro-serverfind-client/client"
	serverfindConfig "zxs-micro-2/zxs-micro-serverfind-client/config"
)

type Server struct {
	services     map[string]*Service
	globalConfig config.BusinessConfig
	servErr      chan error
	router       map[string]methodDescWithPb
}

type Service struct {
	business.UnimplementedBusinessServiceServer
	serviceId   string
	timeout     int64
	grpcServer  *grpc.Server
	netListener net.Listener
}

type BusinessService struct {
	ServicePb   interface{}
	ServiceDesc *grpc.ServiceDesc
}

type methodDescWithPb struct {
	methodDesc grpc.MethodDesc
	servicePb  interface{}
}

var localServer *Server

func (s *Service) ExecBusiness(ctx context.Context,
	request *business.ExecBusinessRequest) (*business.ExecBusinessResponse, error) {
	hm := request.ReqHead.AsMap()
	param := request.ReqParam.AsMap()
	act, ok := param["action"].(string)
	if ok {
		//正经的请求...
		desc, ok := localServer.router[act]
		if ok {
			serializationType := cast.ToInt(hm["SerializationType"])
			rsp, err := desc.methodDesc.Handler(desc.servicePb, ctx,
				func(i interface{}) error {
					err1 := http_codec.HttpSerializerUnMarshal(serializationType, request.ReqParamBytes, i)
					return err1
				}, func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
					handler grpc.UnaryHandler) (interface{}, error) {
					return handler(ctx, req)
				})
			fmt.Println(rsp)
			if err != nil {
				return nil, err
			}
			bs, err := json.Marshal(rsp)
			if err != nil {
				return nil, err
			}
			businessRsp := new(business.ExecBusinessResponse)
			businessRsp.RspParam = bs
			return businessRsp, nil
		}
	}
	fmt.Println(hm)
	fmt.Println(param)
	return &business.ExecBusinessResponse{
		RspParam: []byte(request.ReqParam.String()),
	}, nil
}

func (s *Service) registerSelf(ingress, port, protocol string, servErr chan error) {
	serverfindConfig.Cfg.ServerType = ingress
	serverfindConfig.Cfg.ClientPort = port
	serverfindConfig.Cfg.ClientProtocol = protocol
	id, err := serverfindClient.InitServerFindClient()
	if err != nil {
		servErr <- err
	}
	s.serviceId = id
	balanceConfig.Cfg.SelfIpAddr = serverfindClient.GetSelfIpAddr(context.Background())
	balanceConfig.Cfg.ServiceType = ingress
	balanceClient.InitBalanceClient(id)
}

func InitBusinessCommonService(cfg config.BusinessConfig) {
	localServer = new(Server)
	localServer.services = make(map[string]*Service)
	localServer.router = make(map[string]methodDescWithPb)
	var servErr = make(chan error)
	for _, o := range cfg.ServerConfig.ServiceConfig {
		switch o.Protocol {
		case "grpc":
			initGrpcService(o, servErr)
		case "http":
			initHttpService(o, servErr)
		default:
			//todo 暂时先弄http和grpc吧，其他协议后面再加
			panic(o.Protocol + "是什么协议?")
		}
	}
	localServer.globalConfig = cfg
	localServer.servErr = servErr
}

func initGrpcService(cfg config.Service, servErr chan error) {
	if cfg.Protocol != "grpc" {
		return
	}
	lis, _ := net.Listen("tcp", "localhost"+cfg.Port)
	s := grpc.NewServer()
	healthUtil.InitHealthService(s)
	commonBusinessService := new(Service)
	business.RegisterBusinessServiceServer(s, commonBusinessService)
	commonBusinessService.netListener = lis
	commonBusinessService.timeout, _ = strconv.ParseInt(cfg.Timeout, 10, 64)
	commonBusinessService.grpcServer = s
	localServer.services[cfg.Route] = commonBusinessService
}

func initHttpService(cfg config.Service, servErr chan error) {
	servErr <- errors.New("再等等吧。。。")
}

func RegisterService(serviceName string, bs BusinessService) error {
	sv, ok := localServer.services[serviceName]
	if !ok {
		return consts.SERVER_NOT_FOUND_ERROR
	}
	for _, o := range bs.ServiceDesc.Methods {
		localServer.router[o.MethodName] = methodDescWithPb{
			methodDesc: o, servicePb: bs.ServicePb,
		}
	}
	sv.grpcServer.RegisterService(bs.ServiceDesc, bs.ServicePb)
	return nil
}

func StartServer() {
	for _, cfg := range localServer.globalConfig.ServerConfig.ServiceConfig {
		svic := localServer.services[cfg.Route]
		switch cfg.Protocol {
		case "grpc":
			go func() {
				if err := svic.grpcServer.Serve(svic.netListener); err != nil {
					panic(err)
				}
			}()
			go svic.registerSelf(cfg.Route, cfg.Port, cfg.Protocol, localServer.servErr)
		case "http":

		default:
			//todo 暂时先弄http和grpc吧，其他协议后面再加
			panic(cfg.Protocol + "是什么协议?")
		}
	}
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
	select {
	case <-sigs:
		fmt.Println("服务关闭.....")
	case shuterr := <-localServer.servErr:
		fmt.Println(shuterr)
		fmt.Println("由于出现错误，服务发现关闭......")
	}
	os.Exit(0)
}
